Add PPFrame::isVolatile and PPFrame::setVolatile
authorBrad Jorsch <bjorsch@wikimedia.org>
Fri, 6 Dec 2013 23:28:09 +0000 (18:28 -0500)
committerJackmcbarn <jackmcbarn@gmail.com>
Fri, 30 May 2014 18:07:06 +0000 (14:07 -0400)
Most wikitext is safe to parse once and then cache for when that same
wikitext is used again, such as for multiple transclusions of the same
template within a page. There are occasions, though, where some piece of
wikitext has side effects and so should not be cached; a prominent
example of such wikitext is the <ref> and <references> tags in Cite.php.

This change adds PPFrame::setVolatile so parser hooks such as <ref> and
<references> can indicate that they have done something that should not
be cached, and PPFrame::isVolatile so that callers of PPFrame::expand
can know when to avoid caching.

Bug: 46815
Bug: 31834
Change-Id: I95b3cf8781cf047cdb63da221cef45f3e7d1632e

RELEASE-NOTES-1.24
includes/api/ApiExpandTemplates.php
includes/parser/Parser.php
includes/parser/Preprocessor.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php

index 6a6bcf7..83ced70 100644 (file)
@@ -49,6 +49,9 @@ production.
   ATTENTION: This hook is likely to be removed soon due to overall design of the system.
 * (bug 17367) It is now possible to add pages to your watchlist from
   Special:UnwatchedPages without reloading the special page.
+* New methods setVolatile and isVolatile are added to PPFrame, so that
+  extensions such as Cite.php can mark that their output is volatile and
+  shouldn't be cached.
 
 === Bug fixes in 1.24 ===
 * (bug 49116) Footer copyright notice is now always displayed in user language
index 28ed5e4..b42a30b 100644 (file)
@@ -68,11 +68,15 @@ class ApiExpandTemplates extends ApiBase {
                        ApiResult::setContent( $xml_result, $xml );
                        $result->addValue( null, 'parsetree', $xml_result );
                }
-               $retval = $wgParser->preprocess( $params['text'], $title_obj, $options );
+               $frame = $wgParser->getPreprocessor()->newFrame();
+               $retval = $wgParser->preprocess( $params['text'], $title_obj, $options, null, $frame );
 
                // Return result
                $retval_array = array();
                ApiResult::setContent( $retval_array, $retval );
+               if ( $frame->isVolatile() ) {
+                       $retval_array['volatile'] = '';
+               }
                $result->addValue( null, $this->getModuleName(), $retval_array );
        }
 
index cf174ec..d0d29d3 100644 (file)
@@ -617,13 +617,15 @@ class Parser {
        /**
         * Expand templates and variables in the text, producing valid, static wikitext.
         * Also removes comments.
+        * Do not call this function recursively.
         * @param string $text
         * @param Title $title
         * @param ParserOptions $options
         * @param int|null $revid
+        * @param bool|PPFrame $frame
         * @return mixed|string
         */
-       function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null ) {
+       function preprocess( $text, Title $title = null, ParserOptions $options, $revid = null, $frame = false ) {
                wfProfileIn( __METHOD__ );
                $magicScopeVariable = $this->lock();
                $this->startParse( $title, $options, self::OT_PREPROCESS, true );
@@ -632,7 +634,7 @@ class Parser {
                }
                wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
                wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
-               $text = $this->replaceVariables( $text );
+               $text = $this->replaceVariables( $text, $frame );
                $text = $this->mStripState->unstripBoth( $text );
                wfProfileOut( __METHOD__ );
                return $text;
index 25b34fa..e7ccd10 100644 (file)
@@ -165,6 +165,30 @@ interface PPFrame {
         */
        function isTemplate();
 
+       /**
+        * Set the "volatile" flag.
+        *
+        * Note that this is somewhat of a "hack" in order to make extensions
+        * with side effects (such as Cite) work with the PHP parser. New
+        * extensions should be written in a way that they do not need this
+        * function, because other parsers (such as Parsoid) are not guaranteed
+        * to respect it, and it may be removed in the future.
+        *
+        * @param bool $flag
+        */
+       function setVolatile( $flag = true );
+
+       /**
+        * Get the "volatile" flag.
+        *
+        * Callers should avoid caching the result of an expansion if it has the
+        * volatile flag set.
+        *
+        * @see self::setVolatile()
+        * @return bool
+        */
+       function isVolatile();
+
        /**
         * Get a title of frame
         *
index 4f5ebc8..dbbeddb 100644 (file)
@@ -983,6 +983,8 @@ class PPFrame_DOM implements PPFrame {
         */
        var $depth;
 
+       private $volatile = false;
+
        /**
         * @var array
         */
@@ -1485,6 +1487,24 @@ class PPFrame_DOM implements PPFrame {
        function getTitle() {
                return $this->title;
        }
+
+       /**
+        * Set the volatile flag
+        *
+        * @param bool $flag
+        */
+       function setVolatile( $flag = true ) {
+               $this->volatile = $flag;
+       }
+
+       /**
+        * Get the volatile flag
+        *
+        * @return bool
+        */
+       function isVolatile() {
+               return $this->volatile;
+       }
 }
 
 /**
@@ -1552,10 +1572,14 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
         * @return string
         */
        function cachedExpand( $key, $root, $flags = 0 ) {
-               if ( !isset( $this->parent->childExpansionCache[$key] ) ) {
-                       $this->parent->childExpansionCache[$key] = $this->expand( $root, $flags );
+               if ( isset( $this->parent->childExpansionCache[$key] ) ) {
+                       return $this->parent->childExpansionCache[$key];
                }
-               return $this->parent->childExpansionCache[$key];
+               $retval = $this->expand( $root, $flags );
+               if ( !$this->isVolatile() ) {
+                       $this->parent->childExpansionCache[$key] = $retval;
+               }
+               return $retval;
        }
 
        /**
@@ -1635,6 +1659,11 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
        function isTemplate() {
                return true;
        }
+
+       function setVolatile( $flag = true ) {
+               parent::setVolatile( $flag );
+               $this->parent->setVolatile( $flag );
+       }
 }
 
 /**
index cb652ac..ad61eec 100644 (file)
@@ -919,6 +919,8 @@ class PPFrame_Hash implements PPFrame {
         */
        var $depth;
 
+       private $volatile = false;
+
        /**
         * @var array
         */
@@ -1390,6 +1392,24 @@ class PPFrame_Hash implements PPFrame {
        function getTitle() {
                return $this->title;
        }
+
+       /**
+        * Set the volatile flag
+        *
+        * @param bool $flag
+        */
+       function setVolatile( $flag = true ) {
+               $this->volatile = $flag;
+       }
+
+       /**
+        * Get the volatile flag
+        *
+        * @return bool
+        */
+       function isVolatile() {
+               return $this->volatile;
+       }
 }
 
 /**
@@ -1452,10 +1472,14 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
         * @return string
         */
        function cachedExpand( $key, $root, $flags = 0 ) {
-               if ( !isset( $this->parent->childExpansionCache[$key] ) ) {
-                       $this->parent->childExpansionCache[$key] = $this->expand( $root, $flags );
+               if ( isset( $this->parent->childExpansionCache[$key] ) ) {
+                       return $this->parent->childExpansionCache[$key];
                }
-               return $this->parent->childExpansionCache[$key];
+               $retval = $this->expand( $root, $flags );
+               if ( !$this->isVolatile() ) {
+                       $this->parent->childExpansionCache[$key] = $retval;
+               }
+               return $retval;
        }
 
        /**
@@ -1556,6 +1580,11 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
        function isTemplate() {
                return true;
        }
+
+       function setVolatile( $flag = true ) {
+               parent::setVolatile( $flag );
+               $this->parent->setVolatile( $flag );
+       }
 }
 
 /**